#include "Object.h"
#include "Scope.h"

namespace FlooP
{
	Number::Number (uint32_t val)
	:
		m_val (val)
	{}	

	void Number::set (uint32_t val)
	{
		m_val = val;
	}

	uint32_t Number::val () const
	{
		return m_val;
	}

	Object::Type Number::type () const
	{
		return Object::NUMBER;
	}

	String::String (const std::string& text)
		:
	m_text (text)
	{}

	void String::set (const std::string& text)
	{
		m_text = text;
	}

	const std::string& String::text () const
	{
		return m_text;
	}

	Object::Type String::type () const
	{
		return Object::STRING;
	}

	Procedure::Procedure (const std::string& name)
	:
		m_name  (name),
		m_scope (new Scope ()),
		m_code  (new CodeBlock ())
	{}

	Procedure::Procedure (const std::string& name, const std::vector<std::string>& args)
	:
		m_name  (name),
		m_args  (args),
		m_scope (new Scope ()),
		m_code  (new CodeBlock ())
	{
		for (uint32_t i = 0; i < m_args.size (); i++) {
			m_scope->define (m_args[i]);
		}
	}

	const std::string& Procedure::name () const
	{
		return m_name;
	}

	const std::vector<std::string>& Procedure::args () const
	{
		return m_args;
	}

	std::shared_ptr<CodeBlock> Procedure::code () const
	{
		return m_code;
	}

	std::shared_ptr<Scope> Procedure::scope () const
	{
		return m_scope;
	}

	uint32_t Procedure::get_block_end (uint32_t block_num) const
	{
		for (uint32_t i = 0; i < m_blocks.size (); i++) {
			if (m_blocks[i].first == block_num) {
				return m_blocks[i].second;
			}
		}

		return 0;
	}

	void Procedure::add_block (uint32_t block_num)
	{
		for (uint32_t i = 0; i < m_blocks.size (); i++) {
			if (m_blocks[i].first == block_num) {
				throw Error ("Compiler : Block number '%i' already defined.", block_num);
			}
		}

		m_blocks.push_back (std::pair<uint32_t, uint32_t> (block_num, 0));
	}

	void Procedure::set_block_end (uint32_t block_num, uint32_t index)
	{
		for (uint32_t i = 0; i < m_blocks.size (); i++) {
			if (m_blocks[i].first == block_num) {
				m_blocks[i].second = index;
			}
		}
	}

	void Procedure::fix_abort_quit ()
	{
		for (uint32_t i = 0; i < m_code->m_instructions.size (); i++) {
			if (m_code->m_instructions[i].m_op == OP_ABORT) {
				m_code->m_instructions[i].m_arg = get_block_end (m_code->m_instructions[i].m_arg) + 3;
			} else if (m_code->m_instructions[i].m_op == OP_QUIT) {
				m_code->m_instructions[i].m_arg = get_block_end (m_code->m_instructions[i].m_arg);
			}
		}
	}

	void Procedure::set_scope (std::shared_ptr<Scope> scope)
	{
		m_scope = scope;
	}
}